﻿using System;

namespace InDepth2Demo.Chapter2
{
    public class CovarianceDemo
    {
        // 演示数组的协变以及执行时的类型检查
        public static void TypeCheck()
        {
            //可以运行
            //string[] strings = new string[5];
            //object[] objects = strings;
            //objects[0] = new Product();

            // 协变 ----- 子类转父类
            IFoo<string> fooStr = new Foo();
            IFoo<object> fooObj = fooStr;
            object memberName = fooObj.GetName();
            Console.WriteLine(memberName);

            // 解释：因为 fooObj 跟 fooStr都是指向的同一对象 (new Foo();)，所以当CLR执行 fooObj.GetName() 时
            // 实际上是执行的 new Foo.GetName() 方法，但该方法返回类型是 String 类型，而 IFoo<object> 要求的返回类型是 object，
            // 所以最终执行的是: object memberName = (object)(new Foo().GetName() ):
            //-------------------------------------------------------------------------------------------------------------------------

            // 逆变 ----- 父类转子类
            IBar<object> barObj = new Bar();
            IBar<string> barStr = barObj;
            barStr.Print("Hello World!");

            // 解释： 因为 barObj 和 barStr 指向的都是同一对象(new Bar();)，所以当CLR执行 barStr.Print() 时，
            // 实际执行的是 new Bar().Print() 方法，但该方法的输入参数要求为 object 类型，而
            // barStr.Print() 方法的输入参数是 string 类型，所以实际执行的是
            // new Bar().Print("Hello World!"); // 这里会隐式将 string 转换成 object
        }

        // out 协变
        interface IFoo<out T>
        {
            T GetName();
        }

        class Foo : IFoo<string>
        {
            public string GetName()
            {
                return GetType().Name;
            }
        }

        interface IBar<in T>
        {
            void Print(T value);
        }

        class Bar : IBar<object>
        {
            public void Print(object value)
            {
                Console.WriteLine(value);
            }
        }

        static void Call()
        {
            Action<object> a = (str) => { Console.WriteLine(str); };

        }
    }
}
